﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data;
using CLFramework.Utility;

namespace CLFramework.Data
{
    /// <summary>
    /// 逻辑层事务管理器。仅在逻辑层需要事务管理时使用。
    /// </summary>
    public class TransactionManager : IDisposable
    {
        DataProviderBase db;
        private SqlConnection connection;
        public SqlTransaction transaction;
        private bool transactionStarted;
        private bool disposed; 
        private static object syncRoot = new object();
        
        /// <summary>
        /// 只允许<see cref="TransactionManagerFactory"/>类创建事务管理器。
        /// </summary>
        public TransactionManager(DataProviderBase database)
        {
            db = database;
        }

        /// <summary>
        /// 开始一个新事务。
        /// </summary>
        /// <returns></returns>
        public void BeginTransaction()
        {
            BeginTransaction(IsolationLevel.Unspecified);
        }

        /// <summary>
        /// 开始一个新事务。指定IsolationLevel。
        /// </summary>
        /// <param name="isolationLevel">要使用的IsolationLevel。</param>
        public void BeginTransaction(IsolationLevel isolationLevel)
        {
            if (transactionStarted)
            {
                return;
            }

            connection = db.CreateSqlConnection();

            //打开连接
            try
            {
                connection.Open();
                //打开事务
                transaction = connection.BeginTransaction(isolationLevel);
                transactionStarted = true;
            }
            catch (Exception)
            {
                if (this.connection != null)
                {
                    this.connection.Close();
                }
                if (this.transaction != null)
                {
                    this.transaction.Dispose();
                }
                this.transactionStarted = false;
                throw;
            }
        }

        /// <summary>
        /// 提交事务。
        /// </summary>
        public void Commit()
        {
            if (!this.transactionStarted)
            {
                throw new InvalidOperationException("Transaction needs to begin first.");
            }
            try
            {
                this.transaction.Commit();
            }
            finally
            {
                this.connection.Close();
                this.connection.Dispose();
                this.transaction.Dispose();
                this.transactionStarted = false;
            }
        }

        /// <summary>
        /// 回滚事务。
        /// </summary>
        public void Rollback()
        {
            if (!this.transactionStarted)
            {
                throw new InvalidOperationException("Transaction needs to begin first.");
            }
            try
            {
                this.transaction.Rollback();
            }
            finally
            {
                this.connection.Close();
                this.connection.Dispose();
                this.transaction.Dispose();
                this.transactionStarted = false;
            }
        }

        /// <summary>
        /// 结束事务。
        /// </summary>
        public void EndTransaction()
        {
            if (connection != null)
            {
                try
                {
                    if (this.transactionStarted)
                        this.transaction.Rollback();
                }
                finally
                {
                    this.connection.Close();
                    this.transaction.Dispose();
                    this.transactionStarted = false;
                }
            }
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (!this.disposed)
            {
                lock (syncRoot)
                {
                    this.disposed = true;
                    if (this.transactionStarted)
                    {
                        this.Rollback();
                    }
                }
            }

            if (connection != null)
            {
                try
                {
                    connection.Dispose();
                }
                catch (Exception exception)
                {
                    Log.Exception(exception);
                }
            }

            GC.SuppressFinalize(this);
        }
    }
}
